﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;



namespace NextViewer
{
    public class Spot
    {
        public Spot()
        {
            gps = -1;
            wifi = -1;
            lat = -1;
            lon = -1;
            accuracy = 0;
            speed = 0;
            type = SPOT;
        }
        public int gps;
        public int wifi;
        public double lat;
        public double lon;
        public double accuracy;
        public double speed;
        public DateTime time;
        public int type;

        public const int SPOT = 1;
        public const int LSPOT = 2;
        public const int VSPOT = 3;


        public static int GetSpots(List<Spot> spots,string id, DateTime sday ,DateTime eday)
        {
            DBMS dbm = DBMS.GetDBMS();
            string format = "yyyy-MM-dd HH:mm";
            string[] param = { id, sday.ToString(format), eday.ToString(format) };
            dbm.Request("GET_SPOTS_PE", param);

            dbm.Connect();
            spots.Clear();

            while (dbm.Next())
            {
                Spot spot = new Spot();
                if (dbm.data[0].ToString() != "")
                    spot.time = DateTime.Parse(dbm.data[0].ToString());
                if (dbm.data[1].ToString() != "")
                    spot.wifi = int.Parse(dbm.data[1].ToString());
                if (dbm.data[2].ToString() != "")
                    spot.gps = int.Parse(dbm.data[2].ToString());
                if (dbm.data[3].ToString() != "")
                    spot.lat = double.Parse(dbm.data[3].ToString());
                if (dbm.data[4].ToString() != "")
                    spot.lon = double.Parse(dbm.data[4].ToString());
                if (dbm.data[5].ToString() != "")
                    spot.accuracy = double.Parse(dbm.data[5].ToString());
                if (dbm.data[6].ToString() != "")
                    spot.speed = double.Parse(dbm.data[6].ToString());
                spots.Add(spot);
            }
            dbm.Close();
            return 0;
        }
        
    }
    class LSpot : Spot
    {
        public LSpot()
        {
            gps = -1;
            wifi = -1;
            lat = -1;
            lon = -1;
            accuracy = 0;
            speed = 0;
            type = LSPOT;
            overlapped = 0;
        }
        public LSpot(Spot spot)
        {
            gps = spot.gps;
            wifi = spot.wifi;
            lat = spot.lat;
            lon = spot.lon;
            accuracy = spot.accuracy;
            speed = spot.speed;
            type = LSPOT;
            overlapped = 0;
            time = spot.time;
            tin = spot.time;
        }
        internal int overlapped;
        internal DateTime tin;
        internal DateTime tout;
    }
    class VSpot : Spot
    {
        public VSpot()
        { }
        public VSpot(Spot spot)
        {
            gps = spot.gps;
            wifi = spot.wifi;
            lat = spot.lat;
            lon = spot.lon;
            accuracy = spot.accuracy;
            speed = spot.speed;
            type = VSPOT;
            time = spot.time;
        }
        internal double velocity=0;
        internal double dx;      // vector
        internal double dy;

    }

    class Location
    {

    }

    class Route
    {
        
    }
    class RouteManager
    {
        public RouteManager(Shell sh)
        {
            spots = new List<Spot>();
            //path = new List<Spot>();
            

            shell = sh;
        }
        public void Analysis()
        {
            DateTime dt = shell.mCom.dtStart.Date;
            GetSpots(dt);
            List<Spot> path = new List<Spot>();
            shell.mCom.mnv.SetText("-----------");
            VerifySpots(path);
            DrawSpots(path);
            PrintPath(path);

            /*
            dt = shell.mCom.dtStart.AddDays(1).Date;
            GetSpots(dt);
            List<Spot> path2 = new List<Spot>();
            shell.mCom.mnv.SetText("-----------");
            VerifySpots(path2);
            DrawSpots(path2);
            PrintPath(path2);

            dt = shell.mCom.dtStart.AddDays(3).Date;
            GetSpots(dt);
            List<Spot> path3 = new List<Spot>();
            shell.mCom.mnv.SetText("-----------");
            VerifySpots(path3);
            DrawSpots(path3);
            PrintPath(path3);
            shell.mCom.mnv.SetText("-----------");
            */
        }
        public void PrintPath(List<Spot> path)
        {
            String str="";
            foreach (Spot sp in path)
            {
                str = "["+sp.type +"]("+sp.lat+","+" )" +sp.time;
                if (sp.type == Spot.LSPOT)
                    str += " <overlap:" + ((LSpot)sp).overlapped + "> out:"+((LSpot)sp).tout;
                //else if(sp.type == Spot.VSPOT)
                    
                shell.mCom.mnv.SetText(str);
            }
            shell.mCom.map.InitMarker();

        }
        public void DrawSpots(List<Spot> path)
        {
            shell.mCom.map.InitPath();
            shell.mCom.map.InitMarker();

            foreach (Spot pt in path)
            {
                if (shell.mCom.map.AddPath(pt.lat, pt.lon) == false)
                    break;
                if (pt.type == Spot.LSPOT)
                    shell.mCom.map.AddSeqMarker(pt.lat, pt.lon);

            }
            shell.mCom.mnv.updatePic(shell.mCom.map);
            shell.mCom.mnv.SetText(shell.mCom.map.ToUri().ToString());
        }

        public void VerifySpots(List<Spot> path)
        {
            //lspot vspot
            int i;
            int skiped=0;

            Spot spot,prespot=null;
            LSpot prelspot = null;
            VSpot prevspot = null;
            if (spots.Count < 2)
                return;

            prespot = spots[0];
            for (i = 1; i < spots.Count; i++)
            {
                spot = spots[i];
                if ((spot.gps == -1 || spot.gps == 2))
                   // && (spot.wifi == -1 || spot.wifi != 2))   //off
                {
                    if (spot.lat == -1 || spot.lat == 0 || spot.lon == 0 || spot.lon == -1)
                        continue;
                    double dist = Util.GetDistance(spot, prespot);
                    double speed = dist / (spot.time - spots[i-1].time).TotalSeconds;
                    if (dist == 0 || speed > Glovar.maxSpeed)
                        continue;

                    if (Glovar.networkGap > dist)
                    {

                        if (prespot.type == Spot.LSPOT || prespot.type == Spot.SPOT)
                        {
                            if (prelspot == null)
                            {
                                prelspot = new LSpot(prespot);
                            }
                            prelspot.tout = spot.time;
                            prelspot.overlapped++;
                            prespot = prelspot;
                            continue;
                        }
                        else
                        {
                            //direction analysis
                            //in network we wait 1h ...
                            if ((spot.time - prespot.time).TotalHours > Glovar.networkHour)
                            {
                                //here is location
                                prelspot = new LSpot(prespot);
                                prelspot.tout = spot.time;
                                prelspot.overlapped = skiped + 1;
                                skiped = 0;
                                prespot = prelspot;
                                path.Add(prespot);
                                //if (prespot.type == Spot.LSPOT)
                                //    i = i;

                            }
                            else
                            {
                                skiped++;
                                //skip
                            }
                        }
                    }
                    else // vspot
                    {
                        prevspot = new VSpot(spot);
                        GetDirection(prespot, prevspot);
                        //if ((spot.time - prespot.time).TotalHours > 1)
                        //{
                        //    prespot = new LSpot(prespot);
                        //}
                        //if(prespot.type != Spot.LSPOT)
                        path.Add(prespot);
                        //if (prespot.type == Spot.LSPOT)
                        //    i = i;
                        prespot = prevspot;
                    }
                }
                else//GPS & WIFI
                {
                    
                }
                
            }
            //마지막 노드를 저장합니다.
            if(path.Count == 0)
                path.Add(prespot);
            else if(path[path.Count-1] != prespot)
                path.Add(prespot);
                    
        }
        public void GetDirection(Spot prev, VSpot cur)
        {
            double dx, dy;
            dx = cur.lat - prev.lat;
            dy = cur.lon - prev.lon;

            double len = Math.Sqrt(dx * dx + dy * dy);

            cur.dx = dx / len;
            cur.dy = dy / len;

        }
        public int GetSpots(DateTime day)
        {
            DBMS dbm = DBMS.GetDBMS();
            string[] param = {id,day.Date.ToShortDateString()};
            dbm.Request("GET_SPOTS", param);

            dbm.Connect();
            spots.Clear();

            while (dbm.Next())
            {
                Spot spot = new Spot();
                if (dbm.data[0].ToString() != "")
                    spot.time = DateTime.Parse(dbm.data[0].ToString());
                if (dbm.data[1].ToString() != "")
                    spot.wifi = int.Parse(dbm.data[1].ToString());
                if (dbm.data[2].ToString() != "")
                    spot.gps = int.Parse(dbm.data[2].ToString());
                if (dbm.data[3].ToString() != "")
                    spot.lat = double.Parse(dbm.data[3].ToString());
                if (dbm.data[4].ToString() != "")
                    spot.lon = double.Parse(dbm.data[4].ToString());
                if (dbm.data[5].ToString() != "")
                    spot.accuracy = double.Parse(dbm.data[5].ToString());
                if (dbm.data[6].ToString() != "")
                    spot.speed = double.Parse(dbm.data[6].ToString());
                //if (spot.time.Hour > 8)
                //    break;
                if (spot.time < shell.mCom.dtStart || spot.time > shell.mCom.dtEnd)
                    continue;
                spots.Add(spot);
            }
            dbm.Close();
            return 0;
        }


        /// <summary>
        /// Path duplication
        /// 두개이상의 path를 겹쳐서 원 경로를 유추한다. 
        /// 이런 일을 하는 이유는 Locus based approach에서 좀더 자세한 경로를 제시하기 위함이다.
        /// 자세한 경로는 사람이 할 일을 좀더 정확히 예측할 수 있다.
        /// 목표는 400m 이내의 오차를 구현하는 것이다.
        /// </summary>
        /// 
        public void DuplicationPath(DateTime[] period)
        {
            // Check same Location to Location path

            
            
        }

        internal string id;
        //internal DateTime start;
        //internal DateTime end;
        private List<Spot> spots;
        //private List<Spot> path;
        private Shell shell;
    }
}
